package br.com.sigad.persistencia.dao.documento;



import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.json.simple.JSONObject;

import br.com.sigad.persistencia.dao.DAOGenerico;
import br.com.sigad.persistencia.dao.representacaodigital.RepresentacaoDigitalDAO;
import br.com.sigad.persistencia.dao.tipodocumento.TipoDocumentoDAO;
import br.com.sigad.persistencia.excessoes.DocumentoJaExisteException;
import br.com.sigad.persistencia.excessoes.RepresentacaoDigitalJaExistenteException;
import br.com.sigad.persistencia.model.DocumentoEntity;
import br.com.sigad.persistencia.model.RepresentacaoDigitalEntity;
import br.com.sigad.persistencia.model.TipoDocumentoEntity;

public class DocumentoDAO extends DAOGenerico<DocumentoEntity> {

	public DocumentoDAO() {
		super(DocumentoEntity.class);
	}

	public void cadastrar(DocumentoEntity documento) throws RuntimeException {
		EntityManager em = getEntityManager();
		EntityTransaction transaction = em.getTransaction();

		transaction.begin();

		if (existeDocumentoComADescricao(documento, em)) {
			throw new DocumentoJaExisteException();
		}
		if (existeRepresentacaoDigitalComEsteNome(documento.getRepresentacaoDigital())) {
			throw new RepresentacaoDigitalJaExistenteException();
		}
		TipoDocumentoEntity tipoDocumento = existeTipoDoDocumento(documento.getTipoDocumento());
		if (tipoDocumento != null) {
			documento.setTipoDocumento(tipoDocumento);
		}

		em.persist(documento);
		transaction.commit();
		System.out.println("Documento salvo com sucesso!");
		em.close();

	}

	private TipoDocumentoEntity existeTipoDoDocumento(TipoDocumentoEntity tipoDocumento) {
		return new TipoDocumentoDAO().existeTipoDoDocumento(tipoDocumento);
	}

	private boolean existeRepresentacaoDigitalComEsteNome(RepresentacaoDigitalEntity representacaoDigital) {
		RepresentacaoDigitalDAO representacaoDigitalDAO = new RepresentacaoDigitalDAO();
		return representacaoDigitalDAO.existe(representacaoDigital);
	}

	private boolean existeDocumentoComADescricao(DocumentoEntity documento, EntityManager em) {
		Session session = (Session) em.getDelegate();
		Criteria criteria = session.createCriteria(DocumentoEntity.class).add(Restrictions.eq("descricao", documento.getDescricao()));

		return criteria.uniqueResult() != null;
	}

	public void remover(long codigoDocumento) {
		EntityManager em = getEntityManager();
		EntityTransaction transaction = em.getTransaction();

		transaction.begin();
		DocumentoEntity documento = em.find(DocumentoEntity.class, codigoDocumento);
		em.remove(documento);
		transaction.commit();
		System.out.println("Documento removido com sucesso!");
		em.close();

	}

	public List<DocumentoEntity> listarTodos() {
		EntityManager em = getEntityManager();
		EntityTransaction transaction = em.getTransaction();

		transaction.begin();
		List<DocumentoEntity> resultList = (List<DocumentoEntity>) em.createQuery("from DocumentoEntity", DocumentoEntity.class).getResultList();
		transaction.commit();
		em.close();
		return resultList;

	}

	public List<Map<String, String>> procurarDocumentos(String texto) {
		EntityManager em = getEntityManager();
		EntityTransaction transaction = em.getTransaction();

		transaction.begin();

		Session session = (Session) em.getDelegate();
		Query query = session.createQuery("from DocumentoEntity as doc where upper(doc.descricao) like :descricao order by doc.descricao DESC");
		query.setParameter("descricao", "%" + texto.toUpperCase() + "%");

		List<DocumentoEntity> resultList = (List<DocumentoEntity>) query.list();
		List<Map<String, String>> l1 = new LinkedList<Map<String, String>>();
		for (DocumentoEntity documentoEntity : resultList) {
			Map<String, String> m = new HashMap<String, String>();
			m.put("codigo", documentoEntity.getCodigo().toString());
			m.put("descricao", documentoEntity.getDescricao());
			m.put("nomeArquivo", documentoEntity.getRepresentacaoDigital().getNome());
			l1.add(m);
		}
		transaction.commit();
		em.close();
		return l1;

	}

	public List<Map<String, String>> recuperarDocumentosQueVaoExpirarComAntecedencia(int antecedencia) {
		EntityManager em = getEntityManager();
		EntityTransaction transaction = em.getTransaction();
		transaction.begin();
		Session session = (Session) em.getDelegate();

		Criteria criteria = session.createCriteria(DocumentoEntity.class, "d");

		Calendar dtFinal = GregorianCalendar.getInstance();
		dtFinal.add(GregorianCalendar.DAY_OF_MONTH, antecedencia);
		criteria.add(Restrictions.sqlRestriction("to_date( to_char({alias}.data_criacao,'DD MM YYYY'),'DD MM YYYY') +{alias}.periodo_permanencia between current_date and current_date +5"));
		criteria.setMaxResults(10);
		List<DocumentoEntity> resultList = (List<DocumentoEntity>) criteria.list();
		
		
		List<Map<String, String>> l1 = new LinkedList<Map<String, String>>();
		for (DocumentoEntity documentoEntity : resultList) {
			Map<String, String> m = new HashMap<String, String>();
			m.put("codigo", documentoEntity.getCodigo().toString());
			m.put("descricao", documentoEntity.getDescricao());
			m.put("nomeArquivo", documentoEntity.getRepresentacaoDigital().getNome());
			m.put("localArmazenamento", documentoEntity.getLocalArmazenamentoFisico());
			l1.add(m);
		}

		return l1;

	}

	public JSONObject carregar(Long codigoDocumento) {
		DocumentoEntity documento = getEntityManager().find(DocumentoEntity.class, codigoDocumento);
		
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("codigo", documento.getCodigo());
		jsonObject.put("descricao", documento.getDescricao());
		
		
		
		String format = DateFormat.getDateInstance(SimpleDateFormat.DEFAULT).format(documento.getDataCriacao());
		jsonObject.put("dataCriacao", format);
		jsonObject.put("localArmazenamentoFisico", documento.getLocalArmazenamentoFisico());
		jsonObject.put("periodoPermanencia", documento.getPeriodoPermanencia());
		
		JSONObject representacaoDigital = new JSONObject();
		representacaoDigital.put("codigo", documento.getRepresentacaoDigital().getCodigo());
		representacaoDigital.put("nome", documento.getRepresentacaoDigital().getNome());
		jsonObject.put("representacaoDigital", representacaoDigital);
		
		JSONObject tipoDocumento = new JSONObject();
		tipoDocumento.put("codigo", documento.getTipoDocumento().getCodigo());
		tipoDocumento.put("nome", documento.getTipoDocumento().getNome());
		jsonObject.put("tipoDocumento", tipoDocumento);
		
		return jsonObject;
	}

}
